{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "eager.ipynb",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CCQY7jpBfMur"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "z6X9omPnfO_h",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "2QQJJyDzqGRb"
      },
      "source": [
        "# Eager Execution の基本"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "B1xdylywqUSX"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/eager\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ja/guide/eager.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ja/guide/eager.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs/site/ja/guide/eager.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Download notebook</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0v-hhRA6Nrzt",
        "colab_type": "text"
      },
      "source": [
        "Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳は**ベストエフォート**であるため、この翻訳が正確であることや[英語の公式ドキュメント](https://www.tensorflow.org/?hl=en)の 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリ[tensorflow/docs](https://github.com/tensorflow/docs)にプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 [docs-ja@tensorflow.org メーリングリスト](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ja)にご連絡ください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "EGjDcGxIqEfX"
      },
      "source": [
        "\n",
        "\n",
        "TensorFlow の Eager Execution は、計算グラフの作成と評価を同時におこなう命令的なプログラミングを行うための環境です：\n",
        "オペレーションはあとで実行するための計算グラフでなく、具体的な計算結果の値を返します。\n",
        "この方法を用いることにより、初心者にとって TensorFlow を始めやすくなり、またモデルのデバッグも行いやすくなります。\n",
        "さらにコードの記述量も削減されます。\n",
        "このガイドの内容を実行するためには、対話的インタープリタ `python` を起動し、以下のコードサンプルを実行してください。\n",
        "\n",
        "Eager Execution は研究や実験のための柔軟な機械学習環境として、以下を提供します。\n",
        "\n",
        "* *直感的なインタフェース*— Python のデータ構造を使用して、コードを自然に記述することができます。小規模なモデルとデータに対してすばやく実験を繰り返すことができます。\n",
        "* *より簡単なデバッグ*— ops を直接呼び出すことで、実行中のモデルを調査したり、変更をテストすることができます。 Python 標準のデバッグツールを用いて即座にエラーのレポーティングができます。\n",
        "* *自然な制御フロー*— TensorFlow のグラフ制御フローの代わりに Python の制御フローを利用するため、動的なモデルの作成をシンプルに行うことができます。\n",
        "  \n",
        "Eager Execution は TensorFlow のほとんどのオペレーションとGPUアクセラレーションをサポートします。\n",
        "\n",
        "Note: いくつかのモデルは Eager Execution を有効化することでオーバヘッドが増える可能性があります。\n",
        "パフォーマンス改善を行っていますが、もしも問題を発見したら、バグ報告してベンチマークを共有してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "RBAeIwOMrYk8"
      },
      "source": [
        "## セットアップと基本的な使い方"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ByNsp4VqqEfa",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "try:\n",
        "  # %tensorflow_version only exists in Colab.\n",
        "  %tensorflow_version 2.x  #gpu\n",
        "except Exception:\n",
        "  pass\n",
        "import tensorflow as tf\n",
        "\n",
        "import cProfile"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "48P3-8q4qEfe"
      },
      "source": [
        "TensorFlow 2.0 では、 Eager Execution はデフォルトで有効化されます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "7aFsD8csqEff",
        "colab": {}
      },
      "source": [
        "tf.executing_eagerly()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "x_G1zZT5qEfh"
      },
      "source": [
        "これで TensorFlow のオペレーションを実行してみましょう。結果はすぐに返されます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "9gsI54pbqEfj",
        "colab": {}
      },
      "source": [
        "x = [[2.]]\n",
        "m = tf.matmul(x, x)\n",
        "print(\"hello, {}\".format(m))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ajFn6qsdqEfl"
      },
      "source": [
        "Eager Execution を有効化することで、 TensorFlow の挙動は変わります—TensorFlowは即座に式を評価して結果をPythonに返すようになります。\n",
        "`tf.Tensor` オブジェクトは計算グラフのノードへのシンボリックハンドルの代わりに具体的な値を参照します。\n",
        "セッションの中で構築して実行する計算グラフが存在しないため、`print（）`やデバッガを使って容易に結果を調べることができます。\n",
        "勾配計算を遮ることなくテンソル値を評価、出力、およびチェックすることができます。\n",
        "\n",
        "Eager Execution は、[NumPy](http://www.numpy.org/)と一緒に使うことができます。\n",
        "NumPy のオペレーションは、`tf.Tensor`を引数として受け取ることができます。\n",
        "TensorFlow [math operations](https://www.tensorflow.org/api_guides/python/math_ops) はPython オブジェクトと Numpy array を `tf.Tensor` に変換します。\n",
        "`tf.Tensor.numpy` メソッドはオブジェクトの値を NumPy の `ndarray` 形式で返します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sTO0_5TYqz1n",
        "colab": {}
      },
      "source": [
        "a = tf.constant([[1, 2],\n",
        "                 [3, 4]])\n",
        "print(a)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Dp14YT8Gq4r1",
        "colab": {}
      },
      "source": [
        "# ブロードキャストのサポート\n",
        "b = tf.add(a, 1)\n",
        "print(b)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "69p3waMfq8cQ",
        "colab": {}
      },
      "source": [
        "# オペレータのオーバーロードがサポートされている\n",
        "print(a * b)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "Ui025t1qqEfm",
        "colab": {}
      },
      "source": [
        "# NumPy valueの使用\n",
        "import numpy as np\n",
        "\n",
        "c = np.multiply(a, b)\n",
        "print(c)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Tq_aFRzWrCua",
        "colab": {}
      },
      "source": [
        "# Tensor から numpy の値を得る\n",
        "print(a.numpy())\n",
        "# => [[1 2]\n",
        "#     [3 4]]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "H08f9ss9qEft"
      },
      "source": [
        "## 動的な制御フロー\n",
        "\n",
        "Eager Execution の主要なメリットは、モデルを実行する際にホスト言語のすべての機能性が利用できることです。\n",
        "たとえば、[fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz)が簡単に書けます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "0fudRMeUqEfu",
        "colab": {}
      },
      "source": [
        "def fizzbuzz(max_num):\n",
        "  counter = tf.constant(0)\n",
        "  max_num = tf.convert_to_tensor(max_num)\n",
        "  for num in range(1, max_num.numpy()+1):\n",
        "    num = tf.constant(num)\n",
        "    if int(num % 3) == 0 and int(num % 5) == 0:\n",
        "      print('FizzBuzz')\n",
        "    elif int(num % 3) == 0:\n",
        "      print('Fizz')\n",
        "    elif int(num % 5) == 0:\n",
        "      print('Buzz')\n",
        "    else:\n",
        "      print(num.numpy())\n",
        "    counter += 1"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "P2cKknQWrJLB",
        "colab": {}
      },
      "source": [
        "fizzbuzz(15)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7kA-aC3BqEfy"
      },
      "source": [
        "この関数はテンソル値に依存する条件式を持ち、実行時にこれらの値を表示します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8huKpuuAwICq"
      },
      "source": [
        "## Eager Execution による学習"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mp2lCCZYrxHd"
      },
      "source": [
        "### 勾配の計算\n",
        "\n",
        "[自動微分](https://en.wikipedia.org/wiki/Automatic_differentiation)はニューラルネットワークの学習で利用される[バックプロパゲーション](https://en.wikipedia.org/wiki/Backpropagation)などの機械学習アルゴリズムの実装を行う上で便利です。\n",
        "Eager Executionでは、勾配計算をあとで行うためのオペレーションをトレースするために`tf.GradientTape` を利用します。\n",
        "\n",
        "Eager Execution では、学習や勾配計算に, `tf.GradientTape` を利用できます。これは複雑な学習ループを実行するときに特に役立ちます。\n",
        "\n",
        "各呼び出し中に異なるオペレーションが発生する可能性があるため、すべての forward-pass オペレーションは一つの「テープ」に記録されます。勾配を計算するには、テープを逆方向に再生してから破棄します。特定の `tf.GradientTape`は一つのグラデーションしか計算できません。後続の呼び出しは実行時エラーをスローします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "7g1yWiSXqEf-",
        "colab": {}
      },
      "source": [
        "w = tf.Variable([[1.0]])\n",
        "with tf.GradientTape() as tape:\n",
        "  loss = w * w\n",
        "\n",
        "grad = tape.gradient(loss, w)\n",
        "print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vkHs32GqweYS"
      },
      "source": [
        "### モデル学習\n",
        "\n",
        "以下の example は MNIST という手書き数字分類を行うマルチレイヤーモデルを作成します。\n",
        "Eager Execution 環境における学習可能なグラフを構築するためのオプティマイザーとレイヤーAPIを提示します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "38kymXZowhhz",
        "colab": {}
      },
      "source": [
        "# mnist データのを取得し、フォーマットする\n",
        "(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()\n",
        "\n",
        "dataset = tf.data.Dataset.from_tensor_slices(\n",
        "  (tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),\n",
        "   tf.cast(mnist_labels,tf.int64)))\n",
        "dataset = dataset.shuffle(1000).batch(32)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "rl1K8rOowmwT",
        "colab": {}
      },
      "source": [
        "# モデルを構築する\n",
        "mnist_model = tf.keras.Sequential([\n",
        "  tf.keras.layers.Conv2D(16,[3,3], activation='relu',\n",
        "                         input_shape=(None, None, 1)),\n",
        "  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),\n",
        "  tf.keras.layers.GlobalAveragePooling2D(),\n",
        "  tf.keras.layers.Dense(10)\n",
        "])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fvyk-HgGwxwl"
      },
      "source": [
        "\n",
        "学習を行わずとも、モデルを呼び出して、 Eager Execution により、出力を検査することができます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "BsxystjBwxLS",
        "colab": {}
      },
      "source": [
        "for images,labels in dataset.take(1):\n",
        "  print(\"Logits: \", mnist_model(images[0:1]).numpy())"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Y3PGa8G7qEgB"
      },
      "source": [
        "keras モデルは組み込みで学習のループを回すメソッド `fit` がありますが、よりカスタマイズが必要な場合もあるでしょう。 Eager Executionを用いて実装された学習ループのサンプルを以下に示します："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "bzRhM7JDnaEG",
        "colab": {}
      },
      "source": [
        "optimizer = tf.keras.optimizers.Adam()\n",
        "loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n",
        "\n",
        "loss_history = []"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "tXaupYXRI2YM"
      },
      "source": [
        "Note: モデルの状況を確認したいときは、 `tf.debugging` にある assert 機能を利用してください。この機能は Eager Execution と Graph Execution のどちらでも利用できます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "DDHrigtiCIA4",
        "colab": {}
      },
      "source": [
        "def train_step(images, labels):\n",
        "  with tf.GradientTape() as tape:\n",
        "    logits = mnist_model(images, training=True)\n",
        "    \n",
        "    # assertを入れて出力の型をチェックする。\n",
        "    tf.debugging.assert_equal(logits.shape, (32, 10))\n",
        "    \n",
        "    loss_value = loss_object(labels, logits)\n",
        "\n",
        "  loss_history.append(loss_value.numpy().mean())\n",
        "  grads = tape.gradient(loss_value, mnist_model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "0m1xAXrmqEgJ",
        "colab": {}
      },
      "source": [
        "def train():\n",
        "  for epoch in range(3):\n",
        "    for (batch, (images, labels)) in enumerate(dataset):\n",
        "      train_step(images, labels)\n",
        "    print ('Epoch {} finished'.format(epoch))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "C5dGz0p_nf4W",
        "colab": {}
      },
      "source": [
        "train()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "5vG5ql_2vYB5",
        "colab": {}
      },
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.plot(loss_history)\n",
        "plt.xlabel('Batch #')\n",
        "plt.ylabel('Loss [entropy]')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kKpOlHPLqEgl"
      },
      "source": [
        "### Variablesとオプティマイザ\n",
        "\n",
        "`tf.Variable` オブジェクトは、学習中にアクセスされるミュータブルな `tf.Tensor` 値を格納し、自動微分を容易にします。\n",
        "モデルのパラメータは、変数としてクラスにカプセル化できます。\n",
        "\n",
        "`tf.GradientTape` と共に `tf.Variable` を使うことでモデルパラメータはよりカプセル化されます。たとえば、上の\n",
        "の自動微分の例は以下のように書き換えることができます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "nnQLBYmEqEgm",
        "colab": {}
      },
      "source": [
        "class Model(tf.keras.Model):\n",
        "  def __init__(self):\n",
        "    super(Model, self).__init__()\n",
        "    self.W = tf.Variable(5., name='weight')\n",
        "    self.B = tf.Variable(10., name='bias')\n",
        "  def call(self, inputs):\n",
        "    return inputs * self.W + self.B\n",
        "\n",
        "# 3 ＊ x + 2を近似するトイデータセット\n",
        "NUM_EXAMPLES = 2000\n",
        "training_inputs = tf.random.normal([NUM_EXAMPLES])\n",
        "noise = tf.random.normal([NUM_EXAMPLES])\n",
        "training_outputs = training_inputs * 3 + 2 + noise\n",
        "\n",
        "# 最適化対象のloss関数\n",
        "def loss(model, inputs, targets):\n",
        "  error = model(inputs) - targets\n",
        "  return tf.reduce_mean(tf.square(error))\n",
        "\n",
        "def grad(model, inputs, targets):\n",
        "  with tf.GradientTape() as tape:\n",
        "    loss_value = loss(model, inputs, targets)\n",
        "  return tape.gradient(loss_value, [model.W, model.B])\n",
        "\n",
        "# 定義：\n",
        "# 1. モデル\n",
        "# 2. モデルパラメータに関する損失関数の導関数\n",
        "# 3. 導関数に基づいて変数を更新するストラテジ。\n",
        "model = Model()\n",
        "optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)\n",
        "\n",
        "print(\"Initial loss: {:.3f}\".format(loss(model, training_inputs, training_outputs)))\n",
        "\n",
        "# 学習ループ\n",
        "for i in range(300):\n",
        "  grads = grad(model, training_inputs, training_outputs)\n",
        "  optimizer.apply_gradients(zip(grads, [model.W, model.B]))\n",
        "  if i % 20 == 0:\n",
        "    print(\"Loss at step {:03d}: {:.3f}\".format(i, loss(model, training_inputs, training_outputs)))\n",
        "\n",
        "print(\"Final loss: {:.3f}\".format(loss(model, training_inputs, training_outputs)))\n",
        "print(\"W = {}, B = {}\".format(model.W.numpy(), model.B.numpy()))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rPjb8nRWqEgr"
      },
      "source": [
        "## Eager Execution の途中でオブジェクトのステータスを使用する\n",
        "\n",
        "TF 1.x の Graph Execution では、プログラムの状態（Variableなど）は global collection に格納され、それらの存続期間は `tf.Session` オブジェクトによって管理されます。\n",
        "対照的に、 Eager Execution の間、状態オブジェクトの存続期間は、対応する Python オブジェクトの存続期間によって決定されます。\n",
        "\n",
        "### 変数とオブジェクト\n",
        "\n",
        "Eager Execution の間、変数はオブジェクトへの最後の参照が削除され、その後削除されるまで存続します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "A2boS674qEgs",
        "colab": {}
      },
      "source": [
        "if tf.test.is_gpu_available():\n",
        "  with tf.device(\"gpu:0\"):\n",
        "    v = tf.Variable(tf.random.normal([1000, 1000]))\n",
        "    v = None  # v は GPU メモリを利用しなくなる"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "scMjg6L6qEgv"
      },
      "source": [
        "### オブジェクトベースの保存\n",
        "\n",
        "このセクションは、[チェックポイントの学習の手引き]（./checkpoint.ipynb） の省略版です。\n",
        "\n",
        "`tf.train.Checkpoint` はチェックポイントを用いて `tf.Variable` を保存および復元することができます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "7z5xRfdHzZOQ",
        "colab": {}
      },
      "source": [
        "x = tf.Variable(10.)\n",
        "checkpoint = tf.train.Checkpoint(x=x)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "IffrUVG7zyVb",
        "colab": {}
      },
      "source": [
        "x.assign(2.)   # 新しい値を変数に代入して保存する。\n",
        "checkpoint_path = './ckpt/'\n",
        "checkpoint.save('./ckpt/')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "eMT9koCoqEgw",
        "colab": {}
      },
      "source": [
        "x.assign(11.)  # 保存後に変数の値を変える。\n",
        "\n",
        "# チェックポイントから変数を復元する\n",
        "checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))\n",
        "\n",
        "print(x)  # => 2.0"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vbFnP-yLqEgx"
      },
      "source": [
        "モデルを保存して読み込むために、 `tf.train.Checkpoint` は隠れ変数なしにオブジェクトの内部状態を保存します。 `モデル`、 `オプティマイザ` 、そしてグローバルステップの状態を記録するには、それらを `tf.train.Checkpoint` に渡します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "hWZHyAXMqEg0",
        "colab": {}
      },
      "source": [
        "import os\n",
        "\n",
        "model = tf.keras.Sequential([\n",
        "  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),\n",
        "  tf.keras.layers.GlobalAveragePooling2D(),\n",
        "  tf.keras.layers.Dense(10)\n",
        "])\n",
        "optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)\n",
        "checkpoint_dir = 'path/to/model_dir'\n",
        "if not os.path.exists(checkpoint_dir):\n",
        "  os.makedirs(checkpoint_dir)\n",
        "checkpoint_prefix = os.path.join(checkpoint_dir, \"ckpt\")\n",
        "root = tf.train.Checkpoint(optimizer=optimizer,\n",
        "                           model=model)\n",
        "\n",
        "root.save(checkpoint_prefix)\n",
        "root.restore(tf.train.latest_checkpoint(checkpoint_dir))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "R-ITwkBCF6GJ"
      },
      "source": [
        "多くの学習ループでは、変数は `tf.train..Checkpoint.restore` が呼ばれたあとに作成されます。これらの変数は作成されてすぐに復元され、チェックポイントがすべてロードされたことを確認するためのアサーションが利用可能になります。詳しくは、 [guide to training checkpoints](./checkpoint.ipynb) を見てください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3yoD0VJ7qEg3"
      },
      "source": [
        "### オブジェクト指向メトリクス\n",
        "\n",
        "`tfe.keras.metrics`はオブジェクトとして保存されます。新しいデータを呼び出し可能オブジェクトに渡してメトリクスを更新し、 `tfe.keras.metrics.result`メソッドを使って結果を取得します。次に例を示します:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "9ccu0iAaqEg5",
        "colab": {}
      },
      "source": [
        "m = tf.keras.metrics.Mean(\"loss\")\n",
        "m(0)\n",
        "m(5)\n",
        "m.result()  # => 2.5\n",
        "m([8, 9])\n",
        "m.result()  # => 5.5"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "xEL4yJe5qEhD"
      },
      "source": [
        "## 高度な自動微分トピック\n",
        "\n",
        "### 動的なモデル\n",
        "\n",
        "`tf.GradientTape` は動的モデルでも使うことができます。 \n",
        "以下の [バックトラックライン検索](https://wikipedia.org/wiki/Backtracking_line_search)\n",
        "アルゴリズムの例は、複雑な制御フローにもかかわらず\n",
        "勾配があり、微分可能であることを除いて、通常の NumPy コードのように見えます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "L518n5dkqEhE",
        "colab": {}
      },
      "source": [
        "def line_search_step(fn, init_x, rate=1.0):\n",
        "  with tf.GradientTape() as tape:\n",
        "    # 変数は自動的に記録されるが、Tensorは手動でウォッチする\n",
        "    tape.watch(init_x)\n",
        "    value = fn(init_x)\n",
        "  grad = tape.gradient(value, init_x)\n",
        "  grad_norm = tf.reduce_sum(grad * grad)\n",
        "  init_value = value\n",
        "  while value > init_value - rate * grad_norm:\n",
        "    x = init_x - rate * grad\n",
        "    value = fn(x)\n",
        "    rate /= 2.0\n",
        "  return x, value"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gieGOf_DqEhK"
      },
      "source": [
        "### カスタム勾配\n",
        "\n",
        "カスタム勾配は、勾配を上書きする簡単な方法です。 フォワード関数では、\n",
        "入力、出力、または中間結果に関する勾配を定義します。たとえば、逆方向パスにおいて勾配のノルムを制限する簡単な方法は次のとおりです："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "-OwwsWUAqEhK",
        "colab": {}
      },
      "source": [
        "@tf.custom_gradient\n",
        "def clip_gradient_by_norm(x, norm):\n",
        "  y = tf.identity(x)\n",
        "  def grad_fn(dresult):\n",
        "    return [tf.clip_by_norm(dresult, norm), None]\n",
        "  return y, grad_fn"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JPLDHkF_qEhN"
      },
      "source": [
        "カスタム勾配は、一連の演算に対して数値的に安定した勾配を提供するために共通的に使用されます。:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "24WiLROnqEhO",
        "colab": {}
      },
      "source": [
        "def log1pexp(x):\n",
        "  return tf.math.log(1 + tf.exp(x))\n",
        "\n",
        "def grad_log1pexp(x):\n",
        "  with tf.GradientTape() as tape:\n",
        "    tape.watch(x)\n",
        "    value = log1pexp(x)\n",
        "  return tape.gradient(value, x)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "n8fq69r9-B-c",
        "colab": {}
      },
      "source": [
        "# 勾配計算は x = 0 のときはうまくいく。\n",
        "grad_log1pexp(tf.constant(0.)).numpy()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "_VFSU0mG-FSp",
        "colab": {}
      },
      "source": [
        "# しかし、x = 100のときは数値的不安定により失敗する。\n",
        "grad_log1pexp(tf.constant(100.)).numpy()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-VcTR34rqEhQ"
      },
      "source": [
        "ここで、 `log1pexp` 関数はカスタム勾配を用いて解析的に単純化することができます。\n",
        "以下の実装は、フォワードパスの間に計算された `tf.exp（x）` の値を\n",
        "再利用します—冗長な計算を排除することでより効率的になります："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "Q7nvfx_-qEhS",
        "colab": {}
      },
      "source": [
        "@tf.custom_gradient\n",
        "def log1pexp(x):\n",
        "  e = tf.exp(x)\n",
        "  def grad(dy):\n",
        "    return dy * (1 - 1 / (1 + e))\n",
        "  return tf.math.log(1 + e), grad\n",
        "\n",
        "def grad_log1pexp(x):\n",
        "  with tf.GradientTape() as tape:\n",
        "    tape.watch(x)\n",
        "    value = log1pexp(x)\n",
        "  return tape.gradient(value, x)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "5gHPKMfl-Kge",
        "colab": {}
      },
      "source": [
        "# 上と同様に、勾配計算はx = 0のときにはうまくいきます。\n",
        "grad_log1pexp(tf.constant(0.)).numpy()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "u38MOfz3-MDE",
        "colab": {}
      },
      "source": [
        "# また、勾配計算はx = 100でも機能します。\n",
        "grad_log1pexp(tf.constant(100.)).numpy()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rnZXjfQzqEhV"
      },
      "source": [
        "## パフォーマンス\n",
        "\n",
        "Eager Executionの間、計算は自動的にGPUにオフロードされます。計算を実行するデバイスを指定したい場合は、\n",
        "`tf.device（ '/ gpu：0'）` ブロック（もしくはCPUを指定するブロック）で囲むことで指定できます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "Ac9Y64H-qEhX",
        "colab": {}
      },
      "source": [
        "import time\n",
        "\n",
        "def measure(x, steps):\n",
        "  # TensorFlowはGPUを初めて使用するときに初期化するため、時間計測対象からは除外する。\n",
        "  tf.matmul(x, x)\n",
        "  start = time.time()\n",
        "  for i in range(steps):\n",
        "    x = tf.matmul(x, x)\n",
        "  # ｔｆ．ｍａｔｍｕｌは、行列乗算が完了する前に戻ることができる。\n",
        "  # （たとえば、ＣＵＤＡストリームにオペレーションをエンキューした後に戻すことができる）。\n",
        "  # 以下のx.numpy（）呼び出しは、すべてのキューに入れられたオペレーションが完了したことを確認する。\n",
        "  # （そして結果をホストメモリにコピーするため、計算時間は単純なmatmulオペレーションよりも多くのことを含む時間になる。）\n",
        "  _ = x.numpy()\n",
        "  end = time.time()\n",
        "  return end - start\n",
        "\n",
        "shape = (1000, 1000)\n",
        "steps = 200\n",
        "print(\"Time to multiply a {} matrix by itself {} times:\".format(shape, steps))\n",
        "\n",
        "# CPU上で実行するとき：\n",
        "with tf.device(\"/cpu:0\"):\n",
        "  print(\"CPU: {} secs\".format(measure(tf.random.normal(shape), steps)))\n",
        "\n",
        "# GPU上で実行するとき（GPUが利用できれば）：\n",
        "if tf.test.is_gpu_available():\n",
        "  with tf.device(\"/gpu:0\"):\n",
        "    print(\"GPU: {} secs\".format(measure(tf.random.normal(shape), steps)))\n",
        "else:\n",
        "  print(\"GPU: not found\")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "RLw3IS7UqEhe"
      },
      "source": [
        "`tf.Tensor` オブジェクトはそのオブジェクトに対するオペレーションを実行するために別のデバイスにコピーすることができます："
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "attributes": {
          "classes": [
            "py"
          ],
          "id": ""
        },
        "colab_type": "code",
        "id": "ny6LX2BVqEhf",
        "colab": {}
      },
      "source": [
        "if tf.test.is_gpu_available():\n",
        "  x = tf.random.normal([10, 10])\n",
        "\n",
        "  x_gpu0 = x.gpu()\n",
        "  x_cpu = x.cpu()\n",
        "\n",
        "  _ = tf.matmul(x_cpu, x_cpu)    # CPU上で実行するとき\n",
        "  _ = tf.matmul(x_gpu0, x_gpu0)  # GPU:0上で実行するとき"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "oA_qaII3-p6c"
      },
      "source": [
        "### ベンチマーク\n",
        "\n",
        "GPUでの\n",
        "[ResNet50](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/python/examples/resnet50)\n",
        "の学習のような、計算量の多いモデルの場合は、Eager Executionのパフォーマンスは `tf.function` のパフォーマンスに匹敵します。\n",
        "しかし、この2つの環境下のパフォーマンスの違いは計算量の少ないモデルではより大きくなり、小さなたくさんのオペレーションからなるモデルでホットコードパスを最適化するためにやるべきことがあります。\n",
        "\n",
        "## functionsの利用\n",
        "\n",
        "Eager Execution は開発とデバッグをより対話的にしますが、\n",
        "TensorFlow 1.x スタイルの Graph Execution は分散学習、パフォーマンスの最適化、そしてプロダクション環境へのデプロイの観点で利点があります。\n",
        "\n",
        "2つの手法のギャップを埋めるために、 TensorFlow 2.0 は `ｔｆ．function` という機能を導入しています。\n",
        "詳しくは、 [Autograph](./function.ipynb) のガイドを見てください。\n"
      ]
    }
  ]
}